install.packages("nycflights13")
trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/nycflights13_1.0.1.tgz'
Content type 'application/x-gzip' length 7115754 bytes (6.8 MB)
==================================================
downloaded 6.8 MB

The downloaded binary packages are in
    /var/folders/yq/9s478ryj1fz0t_86x7d9wm240000gn/T//RtmpLNrQbE/downloaded_packages

Chapter 10: Tibbles

Read R4ds Chapter 10: Tibbles, sections 1-3.

10.1: Introduction

library(tidyverse)

10.2: Creating tibbles

Section 10.2: Table 1

Create a tibble from a data frame.

as_tibble(iris)

This chunk give information on sepal length and width, petal length and width, and the species of the iris’.

Section 10.2: Table 2

Tibble with individual vectors.

tibble(x = 1:5, y = 1, z = x ^ 2 + y)

Section 10.2: Table 3

Use of backticks to create column names.

tb <- tibble(`:)` = "smile", ` ` = "space",`2000` = "number") 
tb

Section 10.2: Table 4

Tribble

tribble(
  ~x, ~y, ~z,
  #--|--|----
  "a", 2, 3.6,
  "b", 1, 8.5
)

10.3: Tibbles vs data.frame

10.3.1: Printing

Tibble Print

tibble(
  a = lubridate::now() + runif(1e3) * 86400,
  b = lubridate::today() + runif(1e3) * 30,
  c = 1:1e3,
  d = runif(1e3),
  e = sample(letters, 1e3, replace = TRUE))

Explicit tibble print

nycflights13::flights %>% 
  print(n = 10, width = Inf)

View nycflights13 data set

nycflights13::flights %>% 
  View()

Section 10.3.2: Subsetting

Create a data frame

df <- tibble(
  x = runif(5),
  y = rnorm(5))

Extract a variable by name

df$x
[1] 0.4078880 0.3243437 0.1120017 0.7956879 0.6051586

Extract a variable by name

df[["x"]]
[1] 0.4078880 0.3243437 0.1120017 0.7956879 0.6051586

Extract a variable by position

df[[1]]
[1] 0.4078880 0.3243437 0.1120017 0.7956879 0.6051586

Extract a variable by name with a pipe

df %>% .$x

Extract a variable by position with a pipe

df %>% .[["x"]]
[1] 0.4078880 0.3243437 0.1120017 0.7956879 0.6051586

10.4: Not required

Section 10.5 Questions

Answer the questions completely. Use code chunks, text, or both, as necessary.

1: How can you tell if an object is a tibble? (Hint: try printing mtcars, which is a regular data frame). If an object is a tibble then only the first ten observations will print. You may also use the is_tibble() function to determine if an object is a tibble. Identify at least two ways to tell if an object is a tibble. Hint: What does as_tibble() do? Turns an existing data set into a tibble. What does class() do? Identifies the class of an object. What does str() do? Identifies the basic structure of an object.

mtcars

2: Compare and contrast the following operations on a data.frame and equivalent tibble. What is different? Both are means of calling out data, however the tibble option requires fewer keystrokes. Why might the default data frame behaviours cause you frustration? More keystrokes are required.

df <- data.frame(abc = 1, xyz = "a")
df$x
[1] "a"
df[, "xyz"]
[1] "a"
df[, c("abc", "xyz")]

Chapter 11: Importing data

Read R4ds Chapter 11: Data Import, sections 1, 2, and 5.

11.1 Introduction

Nothing to do here unless you took a break and need to reload tidyverse.

11.2 Getting started.

Do not run the first code chunk of this section, which begins with heights <- read_csv("data/heights.csv"). You do not have that data file so the code will not run.

Enter and run the remaining chunks in this section.

Produces an inline csv file

read_csv("a,b,c
1,2,3
4,5,6")

Create a csv file but skip the first lines

read_csv("The first line of metadata
  The second line of metadata
  x,y,z
  1,2,3", skip = 2)

Create csv file and skip a comment.

read_csv("# A comment I want to skip
  x,y,z
  1,2,3", comment = "#")

Create a csv file that doesn’t have column names on data

read_csv("1,2,3\n4,5,6", col_names = FALSE)

Create a csv file and assign column names a vector

read_csv("1,2,3\n4,5,6", col_names = c("x", "y", "z"))

Create csv file and add na to missing data

read_csv("a,b,c\n1,2,.", na = ".")

11.2 Questions

1: What function would you use to read a file where fields were separated with “|”? read_delim()

2: (This question is modified from the text.) Finish the two lines of read_delim code so that the first one would read a comma-separated file and the second would read a tab-separated file. You only need to worry about the delimiter. Do not worry about other arguments. Replace the dots in each line with the rest of your code.

Comma-separated

file <- read_delim("file.csv", read_csv())

Tab-separated

file <- read_delim("file.csv", read_tsv())

3: What are the two most important arguments to read_fwf()? Why? The two most important arguments are width and position. Because it allows the reading of files with of white space.

4: Skip this question

5: Identify what is wrong with each of the following inline CSV files. What happens when you run the code?

read_csv("a,b\n1,2,3\n4,5,6")
2 parsing failures.
row col  expected    actual         file
  1  -- 2 columns 3 columns literal data
  2  -- 2 columns 3 columns literal data
read_csv("a,b,c\n1,2\n1,2,3,4")
2 parsing failures.
row col  expected    actual         file
  1  -- 3 columns 2 columns literal data
  2  -- 3 columns 4 columns literal data
read_csv("a,b\n\"1")
2 parsing failures.
row col                     expected    actual         file
  1  a  closing quote at end of file           literal data
  1  -- 2 columns                    1 columns literal data
read_csv("a,b\n1,2\na,b")
read_csv("a;b\n1;3")

read_csv(“a,b1,2,34,5,6”)- only two columns are provided, so some data is lost read_csv(“a,b,c1,21,2,3,4”)- only 3 column names are provided so some data is lost read_csv(“a,b"1”)- the quotation marks are not closed read_csv(“a,b1,2,b”)- ?? read_csv(“a;b1;3”)- read_csv() works with commas, doesnt recognize semicolons

11.3 and 11.4: Not required

11.5: Writing to a file

Just read this section. You may find it helpful in the future to save a data file to your hard drive. It is basically the same format as reading a file, except that you must specify the data object to save, in addition to the path and file name.

11.6 Not required

Chapter 18: Pipes

Read R4ds Chapter 18: Pipes, sections 1-3.

Nothing to do otherwise for this chapter. Is this easy or what?

Note: Trying using pipes for all of the remaining examples. That will help you understand them.

Chapter 12: Tidy Data

Read R4ds Chapter 12: Tidy Data, sections 1-3, 7.

12.1 Introduction

Nothing to do here unless you took a break and need to reload the tidyverse.

12.2 Tidy data

Study Figure 12.1 and relate the diagram to the three rules listed just above them. Relate that back to the example I gave you in the notes. Bear this in mind as you make data tidy in the second part of this assignment.

You do not have to run any of the examples in this section.

12.3

Read and run the examples through section 12.3.1 (gathering), including the example with left_join(). We’ll cover joins later.

Table 4a dataset

table4a

Table 4a dataset renaming columns

table4a %>% 
  pivot_longer(c(`1999`, `2000`), names_to = "year", values_to = "cases")

Tidying data into cells

table4b %>% 
  pivot_longer(c(`1999`, `2000`), names_to = "year", values_to = "population")

Tidy table 4a

tidy4a <- table4a %>% 
  pivot_longer(c(`1999`, `2000`), names_to = "year", values_to = "cases")

Tidy table 4b

tidy4b <- table4b %>% 
  pivot_longer(c(`1999`, `2000`), names_to = "year", values_to = "population")

Left to join table 4a and table 4b.

left_join(tidy4a, tidy4b)
Joining, by = c("country", "year")

Load Table 2

table2

Using pivot wider to create a new column

table2 %>%
    pivot_wider(names_from = type, values_from = count)

12.3 Questions

2: Why does this code fail? Pivot_longer was omitted, so were quotation marks around 1999 and 2000. Fix it so it works.

Orininal Chunk

table4a %>% 
  gather(1999, 2000, key = "year", value = "cases")
#> Error in inds_combine(.vars, ind_list): Position must be between 0 and n

Fixed Chunk

table4a %>% 
  pivot_longer(c(`1999`, `2000`), names_to = "year", values_to = "cases")

That is all for Chapter 12. On to the last chapter.

Chapter 5: Data transformation

Read R4ds Chapter 5: Data Transformation, sections 1-4.

Time to get small.

5.1: Introduction

Load the necessary libraries. As usual, type the examples into and run the code chunks.

library(tidyverse)
library(nycflights13)

Loading Flights

flights

5.2: Filter rows with filter()

Study Figure 5.1 carefully. Once you learn the &, |, and ! logic, you will find them to be very powerful tools.

Filter flights by day and time

filter(flights, month == 1, day == 1)

Save the results 01/01

jan1 <- filter(flights, month == 1, day == 1)

Save and print the results of flights on 12/25

(dec25 <- filter(flights, month == 12, day == 25))

Not using == error

filter(flights, month = 1)
Error: Problem with `filter()` input `..1`.
x Input `..1` is named.
ℹ This usually means that you've used `=` instead of `==`.
ℹ Did you mean `month == 1`?

Floating number results

sqrt(2) ^ 2 == 2
[1] FALSE

Use of near

near(sqrt(2) ^ 2,  2)
[1] TRUE

Use of near

near(1 / 49 * 49, 1)
[1] TRUE

All flights that departed in Nov or Dec

filter(flights, month == 11 | month == 12)

Sgorthand to find all nov and dec flights

nov_dec <- filter(flights, month %in% c(11, 12))

Flights that weren’t delayed by more than two hours.

filter(flights, !(arr_delay > 120 | dep_delay > 120))

Flights that weren’t delayed by more than 2 hours

filter(flights, arr_delay <= 120, dep_delay <= 120)

Creating data frame

df <- tibble(x = c(1, NA, 3))

Apply filter

df <- tibble(x = c(1, NA, 3))
filter(df, x > 1)

Apply filter

filter(df, is.na(x) | x > 1)

5.2 Questions

1.1: Find all flights with a delay of 2 hours or more.

filter(flights, dep_delay >=120) 

1.2: Flew to Houston (IAH or HOU)

filter(flights, dest == "IAH" | dest== "HOU")

1.3: Were operated by United (UA), American (AA), or Delta (DL).

filter(flights, carrier =="UA" | carrier == "AA" | carrier == "DL")

1.4: Departed in summer (July, August, and September).

filter(flights, month =="7" | month == "8" | month == "9")

1.5: Arrived more than two hours late, but didn’t leave late.

filter(flights, dep_delay == 0 & arr_delay >= 120)

1.6: Were delayed by at least an hour, but made up over 30 minutes in flight. This is a tricky one. Do your best.

filter(flights, dep_delay >= 60 & arr_delay <= 30)

1.7: Departed between midnight and 6am (inclusive)

filter(flights, dep_time >= 0000 & dep_time <=600)

2: Another useful dplyr filtering helper is between(). What does it do? Can you use it to simplify the code needed to answer the previous challenges?

Between is a shortcut for less than and equal to and greater than and equal to. Yes, 1.7 couldve been shortcutted by

filter(flights, between(dep_time, 0 , 600))

3: How many flights have a missing dep_time? 8255 flights What other variables are missing? Departure delay, air time, arrival time, and arrival delay. What might these rows represent? The flights never left.

sum(is.na(flights$dep_time))
[1] 8255
filter(flights, is.na(dep_time))

4: Why is NA ^ 0 not missing? NA raised to the power of zero a value, zero. Why is NA | TRUE not missing? Anything ‘or true’ is always true. Why is FALSE & NA not missing? Anything ‘and false’ is always false. Can you figure out the general rule? (NA * 0 is a tricky counterexample!)

Note: For some context, see this thread

5.3 Arrange with arrange()

Arrange flights

arrange(flights, year, month, day)

reorder columns by decending order

arrange(flights, desc(dep_delay))

Create data frame

df <- tibble(x = c(5, 2, NA))

Sort Missing Values

arrange(df, x)

Sort missing values

arrange(df, desc(x))

5.3 Questions

1: How could you use arrange() to sort all missing values to the start? (Hint: use is.na()). Note: This one should still have the earliest departure dates after the NAs. Hint: What does desc() do?

arrange(flights, desc(is.na(dep_delay)))

2: Sort flights to find the most delayed flights. Find the flights that left earliest. Most delayed flights

arrange(flights, desc(dep_delay))

Flights that left the earliest

arrange(flights, dep_delay)

This question is asking for the flights that were most delayed (left latest after scheduled departure time) and least delayed (left ahead of scheduled time).

3: Sort flights to find the fastest flights. Interpret fastest to mean shortest time in the air.

Fastest flights

arrange(flights, air_time)

Optional challenge: fastest flight could refer to fastest air speed. Speed is measured in miles per hour but time is minutes. Arrange the data by fastest air speed.

4: Which flights travelled the longest? Which travelled the shortest? Flights that travelled the longest

arrange(flights, desc(distance))

Flights travelled the shortest

arrange(flights, distance)

5.4 Select columns with select()

Select columns by name

select(flights, year, month, day)

Select all columns btwn year and day (invlusive)

select(flights, year:day)

Select all columns except those from year to day (inclusive)

select(flights, -(year:day))

Rename variables

rename(flights, tail_num = tailnum)

move variables to start of data frame

select(flights, time_hour, air_time, everything())

5.4 Questions

1: Brainstorm as many ways as possible to select dep_time, dep_delay, arr_time, and arr_delay from flights. Find at least three ways. use the deslect function

select(flights, dep_time, dep_delay, arr_time, arr_delay)

Use the starts with function

select(flights, starts_with('dep'), starts_with('arr'))

use contains()

select(flights, contains('delays'), contains('time')) 

2: What happens if you include the name of a variable multiple times in a select() call?

The variables you repeat will be omitted

3: What does the one_of() function do? Why might it be helpful in conjunction with this vector?

vars <- c("year", "month", "day", "dep_delay", "arr_delay")

One_of() allows you to select parts of the dataframe. There may only be a set number of columns and information.

4: Does the result of running the following code surprise you? How do the select helpers deal with case by default? How can you change that default?

select(flights, contains("TIME"))

select(flights, contains('TIME'))

Yes, because R is case sensitive but apparently contains() is not.

LS0tCnRpdGxlOiAiSFcwNiBQYXJ0IDE6IENvbXBsZXRlIHRoZSBzZWN0aW9ucyIKYXV0aG9yOiAiQWxpc3NhIFNlYWwiCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCICVZJylgIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCmBgYHtyfQppbnN0YWxsLnBhY2thZ2VzKCJueWNmbGlnaHRzMTMiKQpgYGAKCi0gQ2hhbmdlICJ5b3VyIG5hbWUiIGluIHRoZSBZQU1MIGhlYWRlciBhYm92ZSB0byB5b3VyIG5hbWUuCgotIEFzIHVzdWFsLCBlbnRlciB0aGUgZXhhbXBsZXMgaW4gY29kZSBjaHVua3MgYW5kIHJ1biB0aGVtLCB1bmxlc3MgdG9sZCBvdGhlcndpc2UuCgojIyBDaGFwdGVyIDEwOiBUaWJibGVzCgpSZWFkIFtSNGRzIENoYXB0ZXIgMTA6IFRpYmJsZXNdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovdGliYmxlcy5odG1sKSwgc2VjdGlvbnMgMS0zLgoKIyMjIDEwLjE6IEludHJvZHVjdGlvbgoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKIAoKIyMjIDEwLjI6IENyZWF0aW5nIHRpYmJsZXMKCgojIyBTZWN0aW9uIDEwLjI6IFRhYmxlIDEKQ3JlYXRlIGEgdGliYmxlIGZyb20gYSBkYXRhIGZyYW1lLiAKCmBgYHtyfQphc190aWJibGUoaXJpcykKYGBgClRoaXMgY2h1bmsgZ2l2ZSBpbmZvcm1hdGlvbiBvbiBzZXBhbCBsZW5ndGggYW5kIHdpZHRoLCBwZXRhbCBsZW5ndGggYW5kIHdpZHRoLCBhbmQgdGhlIHNwZWNpZXMgb2YgdGhlIGlyaXMnLiAKCiMjIFNlY3Rpb24gMTAuMjogVGFibGUgMgoKVGliYmxlIHdpdGggaW5kaXZpZHVhbCB2ZWN0b3JzLiAKCmBgYHtyfQp0aWJibGUoeCA9IDE6NSwgeSA9IDEsIHogPSB4IF4gMiArIHkpCmBgYAoKIyMgU2VjdGlvbiAxMC4yOiBUYWJsZSAzCgpVc2Ugb2YgYmFja3RpY2tzIHRvIGNyZWF0ZSBjb2x1bW4gbmFtZXMuCgpgYGB7cn0KdGIgPC0gdGliYmxlKGA6KWAgPSAic21pbGUiLCBgIGAgPSAic3BhY2UiLGAyMDAwYCA9ICJudW1iZXIiKSAKdGIKYGBgCgoKIyMgU2VjdGlvbiAxMC4yOiBUYWJsZSA0CgpUcmliYmxlIAoKYGBge3J9CnRyaWJibGUoCiAgfngsIH55LCB+eiwKICAjLS18LS18LS0tLQogICJhIiwgMiwgMy42LAogICJiIiwgMSwgOC41CikKYGBgCgoKIyMjIDEwLjM6IFRpYmJsZXMgdnMgZGF0YS5mcmFtZQoKIyMgMTAuMy4xOiBQcmludGluZwoKVGliYmxlIFByaW50IAoKYGBge3J9CnRpYmJsZSgKICBhID0gbHVicmlkYXRlOjpub3coKSArIHJ1bmlmKDFlMykgKiA4NjQwMCwKICBiID0gbHVicmlkYXRlOjp0b2RheSgpICsgcnVuaWYoMWUzKSAqIDMwLAogIGMgPSAxOjFlMywKICBkID0gcnVuaWYoMWUzKSwKICBlID0gc2FtcGxlKGxldHRlcnMsIDFlMywgcmVwbGFjZSA9IFRSVUUpKQpgYGAKCkV4cGxpY2l0IHRpYmJsZSBwcmludCAKCmBgYHtyfQpueWNmbGlnaHRzMTM6OmZsaWdodHMgJT4lIAogIHByaW50KG4gPSAxMCwgd2lkdGggPSBJbmYpCmBgYAoKVmlldyBueWNmbGlnaHRzMTMgZGF0YSBzZXQKCmBgYHtyfQpueWNmbGlnaHRzMTM6OmZsaWdodHMgJT4lIAogIFZpZXcoKQpgYGAKCiMjIyBTZWN0aW9uIDEwLjMuMjogU3Vic2V0dGluZwoKQ3JlYXRlIGEgZGF0YSBmcmFtZQoKYGBge3J9CmRmIDwtIHRpYmJsZSgKICB4ID0gcnVuaWYoNSksCiAgeSA9IHJub3JtKDUpKQpgYGAKCkV4dHJhY3QgYSB2YXJpYWJsZSBieSBuYW1lCmBgYHtyfQpkZiR4CmBgYAoKRXh0cmFjdCBhIHZhcmlhYmxlIGJ5IG5hbWUKCmBgYHtyfQpkZltbIngiXV0KYGBgCgpFeHRyYWN0IGEgdmFyaWFibGUgYnkgcG9zaXRpb24KCmBgYHtyfQpkZltbMV1dCmBgYAoKRXh0cmFjdCBhIHZhcmlhYmxlIGJ5IG5hbWUgd2l0aCBhIHBpcGUKYGBge3J9CmRmICU+JSAuJHgKYGBgCgpFeHRyYWN0IGEgdmFyaWFibGUgYnkgcG9zaXRpb24gd2l0aCBhIHBpcGUKYGBge3J9CmRmICU+JSAuW1sieCJdXQpgYGAKCiMjIyAxMC40OiBOb3QgcmVxdWlyZWQKCiMjIyMgU2VjdGlvbiAxMC41IFF1ZXN0aW9ucwoKQW5zd2VyIHRoZSBxdWVzdGlvbnMgKmNvbXBsZXRlbHkuKiBVc2UgY29kZSBjaHVua3MsIHRleHQsIG9yIGJvdGgsIGFzIG5lY2Vzc2FyeS4KCioqMToqKiBIb3cgY2FuIHlvdSB0ZWxsIGlmIGFuIG9iamVjdCBpcyBhIHRpYmJsZT8gKEhpbnQ6IHRyeSBwcmludGluZyBgbXRjYXJzYCwgd2hpY2ggaXMgYSByZWd1bGFyIGRhdGEgZnJhbWUpLiBJZiBhbiBvYmplY3QgaXMgYSB0aWJibGUgdGhlbiBvbmx5IHRoZSBmaXJzdCB0ZW4gb2JzZXJ2YXRpb25zIHdpbGwgcHJpbnQuIFlvdSBtYXkgYWxzbyB1c2UgdGhlIGlzX3RpYmJsZSgpIGZ1bmN0aW9uIHRvIGRldGVybWluZSBpZiBhbiBvYmplY3QgaXMgYSB0aWJibGUuIElkZW50aWZ5IGF0IGxlYXN0IHR3byB3YXlzIHRvIHRlbGwgaWYgYW4gb2JqZWN0IGlzIGEgdGliYmxlLiAqSGludDoqIFdoYXQgZG9lcyBgYXNfdGliYmxlKClgIGRvPyBUdXJucyBhbiBleGlzdGluZyBkYXRhIHNldCBpbnRvIGEgdGliYmxlLiBXaGF0IGRvZXMgYGNsYXNzKClgIGRvPyBJZGVudGlmaWVzIHRoZSBjbGFzcyBvZiBhbiBvYmplY3QuIFdoYXQgZG9lcyBgc3RyKClgIGRvPyBJZGVudGlmaWVzIHRoZSBiYXNpYyBzdHJ1Y3R1cmUgb2YgYW4gb2JqZWN0LgoKYGBge3J9Cm10Y2FycwpgYGAKCgoqKjI6KiogQ29tcGFyZSBhbmQgY29udHJhc3QgdGhlIGZvbGxvd2luZyBvcGVyYXRpb25zIG9uIGEgZGF0YS5mcmFtZSBhbmQgZXF1aXZhbGVudCB0aWJibGUuIFdoYXQgaXMgZGlmZmVyZW50PyBCb3RoIGFyZSBtZWFucyBvZiBjYWxsaW5nIG91dCBkYXRhLCBob3dldmVyIHRoZSB0aWJibGUgb3B0aW9uIHJlcXVpcmVzIGZld2VyIGtleXN0cm9rZXMuIFdoeSBtaWdodCB0aGUgZGVmYXVsdCBkYXRhIGZyYW1lIGJlaGF2aW91cnMgY2F1c2UgeW91IGZydXN0cmF0aW9uPyBNb3JlIGtleXN0cm9rZXMgYXJlIHJlcXVpcmVkLgoKYGBge3J9CmRmIDwtIGRhdGEuZnJhbWUoYWJjID0gMSwgeHl6ID0gImEiKQpkZiR4CmRmWywgInh5eiJdCmRmWywgYygiYWJjIiwgInh5eiIpXQpgYGAKCgojIyBDaGFwdGVyIDExOiBJbXBvcnRpbmcgZGF0YQoKUmVhZCBbUjRkcyBDaGFwdGVyIDExOiBEYXRhIEltcG9ydF0oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei9kYXRhLWltcG9ydC5odG1sKSwgc2VjdGlvbnMgMSwgMiwgYW5kIDUuCgojIyMgMTEuMSBJbnRyb2R1Y3Rpb24KCk5vdGhpbmcgdG8gZG8gaGVyZSB1bmxlc3MgeW91IHRvb2sgYSBicmVhayBhbmQgbmVlZCB0byByZWxvYWQgYHRpZHl2ZXJzZWAuCgojIyMgMTEuMiBHZXR0aW5nIHN0YXJ0ZWQuCgpEbyAqbm90KiBydW4gdGhlIGZpcnN0IGNvZGUgY2h1bmsgb2YgdGhpcyBzZWN0aW9uLCB3aGljaCBiZWdpbnMgd2l0aCBgaGVpZ2h0cyA8LSByZWFkX2NzdigiZGF0YS9oZWlnaHRzLmNzdiIpYC4gWW91IGRvIG5vdCBoYXZlIHRoYXQgZGF0YSBmaWxlIHNvIHRoZSBjb2RlIHdpbGwgbm90IHJ1bi4KCkVudGVyIGFuZCBydW4gdGhlIHJlbWFpbmluZyBjaHVua3MgaW4gdGhpcyBzZWN0aW9uLgoKUHJvZHVjZXMgYW4gaW5saW5lIGNzdiBmaWxlCgpgYGB7cn0KcmVhZF9jc3YoImEsYixjCjEsMiwzCjQsNSw2IikKYGBgCgpDcmVhdGUgYSBjc3YgZmlsZSBidXQgc2tpcCB0aGUgZmlyc3QgbGluZXMKCmBgYHtyfQpyZWFkX2NzdigiVGhlIGZpcnN0IGxpbmUgb2YgbWV0YWRhdGEKICBUaGUgc2Vjb25kIGxpbmUgb2YgbWV0YWRhdGEKICB4LHksegogIDEsMiwzIiwgc2tpcCA9IDIpCmBgYAoKQ3JlYXRlIGNzdiBmaWxlIGFuZCBza2lwIGEgY29tbWVudC4gCgpgYGB7cn0KcmVhZF9jc3YoIiMgQSBjb21tZW50IEkgd2FudCB0byBza2lwCiAgeCx5LHoKICAxLDIsMyIsIGNvbW1lbnQgPSAiIyIpCmBgYApDcmVhdGUgYSBjc3YgZmlsZSB0aGF0IGRvZXNuJ3QgaGF2ZSBjb2x1bW4gbmFtZXMgb24gZGF0YQoKYGBge3J9CnJlYWRfY3N2KCIxLDIsM1xuNCw1LDYiLCBjb2xfbmFtZXMgPSBGQUxTRSkKYGBgCgpDcmVhdGUgYSBjc3YgZmlsZSBhbmQgYXNzaWduIGNvbHVtbiBuYW1lcyBhIHZlY3RvcgoKYGBge3J9CnJlYWRfY3N2KCIxLDIsM1xuNCw1LDYiLCBjb2xfbmFtZXMgPSBjKCJ4IiwgInkiLCAieiIpKQpgYGAKCkNyZWF0ZSBjc3YgZmlsZSBhbmQgYWRkIG5hIHRvIG1pc3NpbmcgZGF0YQoKYGBge3J9CnJlYWRfY3N2KCJhLGIsY1xuMSwyLC4iLCBuYSA9ICIuIikKYGBgCgoKIyMjIyAxMS4yIFF1ZXN0aW9ucwoKKioxOioqIFdoYXQgZnVuY3Rpb24gd291bGQgeW91IHVzZSB0byByZWFkIGEgZmlsZSB3aGVyZSBmaWVsZHMgd2VyZSBzZXBhcmF0ZWQgd2l0aCAifCI/CnJlYWRfZGVsaW0oKQoKCioqMjoqKiAoVGhpcyBxdWVzdGlvbiBpcyBtb2RpZmllZCBmcm9tIHRoZSB0ZXh0LikgRmluaXNoIHRoZSB0d28gbGluZXMgb2YgYHJlYWRfZGVsaW1gIGNvZGUgc28gdGhhdCB0aGUgZmlyc3Qgb25lIHdvdWxkIHJlYWQgYSBjb21tYS1zZXBhcmF0ZWQgZmlsZSBhbmQgdGhlIHNlY29uZCB3b3VsZCByZWFkIGEgdGFiLXNlcGFyYXRlZCBmaWxlLiBZb3Ugb25seSBuZWVkIHRvIHdvcnJ5IGFib3V0IHRoZSBkZWxpbWl0ZXIuIERvIG5vdCB3b3JyeSBhYm91dCBvdGhlciBhcmd1bWVudHMuIFJlcGxhY2UgdGhlIGRvdHMgaW4gZWFjaCBsaW5lIHdpdGggdGhlIHJlc3Qgb2YgeW91ciBjb2RlLiAKCiMgQ29tbWEtc2VwYXJhdGVkCmBmaWxlIDwtIHJlYWRfZGVsaW0oImZpbGUuY3N2IiwgcmVhZF9jc3YoKSlgCgojIFRhYi1zZXBhcmF0ZWQKYGZpbGUgPC0gcmVhZF9kZWxpbSgiZmlsZS5jc3YiLCByZWFkX3RzdigpKWAKCgoqKjM6KiogV2hhdCBhcmUgdGhlIHR3byBtb3N0IGltcG9ydGFudCBhcmd1bWVudHMgdG8gYHJlYWRfZndmKClgPyBXaHk/ClRoZSB0d28gbW9zdCBpbXBvcnRhbnQgYXJndW1lbnRzIGFyZSB3aWR0aCBhbmQgcG9zaXRpb24uIEJlY2F1c2UgaXQgYWxsb3dzIHRoZSByZWFkaW5nIG9mIGZpbGVzIHdpdGggb2Ygd2hpdGUgc3BhY2UuCgoqKjQ6KiogU2tpcCB0aGlzIHF1ZXN0aW9uCgoKKio1OiAqKiBJZGVudGlmeSB3aGF0IGlzIHdyb25nIHdpdGggZWFjaCBvZiB0aGUgZm9sbG93aW5nIGlubGluZSBDU1YgZmlsZXMuIFdoYXQgaGFwcGVucyB3aGVuIHlvdSBydW4gdGhlIGNvZGU/CgpgYGB7cn0KcmVhZF9jc3YoImEsYlxuMSwyLDNcbjQsNSw2IikKcmVhZF9jc3YoImEsYixjXG4xLDJcbjEsMiwzLDQiKQpyZWFkX2NzdigiYSxiXG5cIjEiKQpyZWFkX2NzdigiYSxiXG4xLDJcbmEsYiIpCnJlYWRfY3N2KCJhO2JcbjE7MyIpCmBgYApyZWFkX2NzdigiYSxiXG4xLDIsM1xuNCw1LDYiKS0gb25seSB0d28gY29sdW1ucyBhcmUgcHJvdmlkZWQsIHNvIHNvbWUgZGF0YSBpcyBsb3N0CnJlYWRfY3N2KCJhLGIsY1xuMSwyXG4xLDIsMyw0IiktIG9ubHkgMyBjb2x1bW4gbmFtZXMgYXJlIHByb3ZpZGVkIHNvIHNvbWUgZGF0YSBpcyBsb3N0CnJlYWRfY3N2KCJhLGJcblwiMSIpLSB0aGUgcXVvdGF0aW9uIG1hcmtzIGFyZSBub3QgY2xvc2VkCnJlYWRfY3N2KCJhLGJcbjEsMlxuYSxiIiktID8/CnJlYWRfY3N2KCJhO2JcbjE7MyIpLSByZWFkX2NzdigpIHdvcmtzIHdpdGggY29tbWFzLCBkb2VzbnQgcmVjb2duaXplIHNlbWljb2xvbnMgCgojIyMgMTEuMyBhbmQgMTEuNDogTm90IHJlcXVpcmVkCgojIyMgMTEuNTogV3JpdGluZyB0byBhIGZpbGUKCkp1c3QgcmVhZCB0aGlzIHNlY3Rpb24uIFlvdSBtYXkgZmluZCBpdCBoZWxwZnVsIGluIHRoZSBmdXR1cmUgdG8gc2F2ZSBhIGRhdGEgZmlsZSB0byB5b3VyIGhhcmQgZHJpdmUuIEl0IGlzIGJhc2ljYWxseSB0aGUgc2FtZSBmb3JtYXQgYXMgcmVhZGluZyBhIGZpbGUsIGV4Y2VwdCB0aGF0IHlvdSBtdXN0IHNwZWNpZnkgdGhlIGRhdGEgb2JqZWN0IHRvIHNhdmUsIGluIGFkZGl0aW9uIHRvIHRoZSBwYXRoIGFuZCBmaWxlIG5hbWUuCgojIyMgMTEuNiBOb3QgcmVxdWlyZWQKCiMjIENoYXB0ZXIgMTg6IFBpcGVzCgpSZWFkIFtSNGRzIENoYXB0ZXIgMTg6IFBpcGVzXShodHRwczovL3I0ZHMuaGFkLmNvLm56L3BpcGVzLmh0bWwpLCBzZWN0aW9ucyAxLTMuCgpOb3RoaW5nIHRvIGRvIG90aGVyd2lzZSBmb3IgdGhpcyBjaGFwdGVyLiBJcyB0aGlzIGVhc3kgb3Igd2hhdD8KCioqTm90ZToqKiBUcnlpbmcgdXNpbmcgcGlwZXMgZm9yIGFsbCBvZiB0aGUgcmVtYWluaW5nIGV4YW1wbGVzLiBUaGF0IHdpbGwgaGVscCB5b3UgdW5kZXJzdGFuZCB0aGVtLgoKIyMgQ2hhcHRlciAxMjogVGlkeSBEYXRhCgpSZWFkIFtSNGRzIENoYXB0ZXIgMTI6IFRpZHkgRGF0YV0oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei90aWR5LWRhdGEuaHRtbCksIHNlY3Rpb25zIDEtMywgNy4gCgojIyMgMTIuMSBJbnRyb2R1Y3Rpb24KCk5vdGhpbmcgdG8gZG8gaGVyZSB1bmxlc3MgeW91IHRvb2sgYSBicmVhayBhbmQgbmVlZCB0byByZWxvYWQgdGhlIGB0aWR5dmVyc2UuYAoKIyMjIDEyLjIgVGlkeSBkYXRhCgpTdHVkeSBGaWd1cmUgMTIuMSBhbmQgcmVsYXRlIHRoZSBkaWFncmFtIHRvIHRoZSB0aHJlZSBydWxlcyBsaXN0ZWQganVzdCBhYm92ZSB0aGVtLiBSZWxhdGUgdGhhdCBiYWNrIHRvIHRoZSBleGFtcGxlIEkgZ2F2ZSB5b3UgaW4gdGhlIG5vdGVzLiBCZWFyIHRoaXMgaW4gbWluZCBhcyB5b3UgbWFrZSBkYXRhIHRpZHkgaW4gdGhlIHNlY29uZCBwYXJ0IG9mIHRoaXMgYXNzaWdubWVudC4KCllvdSBkbyBub3QgaGF2ZSB0byBydW4gYW55IG9mIHRoZSBleGFtcGxlcyBpbiB0aGlzIHNlY3Rpb24uCgojIyMgMTIuMwoKUmVhZCBhbmQgcnVuIHRoZSBleGFtcGxlcyB0aHJvdWdoIHNlY3Rpb24gMTIuMy4xIChnYXRoZXJpbmcpLCBpbmNsdWRpbmcgdGhlIGV4YW1wbGUgd2l0aCBgbGVmdF9qb2luKClgLiBXZSdsbCBjb3ZlciBqb2lucyBsYXRlci4KClRhYmxlIDRhIGRhdGFzZXQKCmBgYHtyfQp0YWJsZTRhCmBgYAoKVGFibGUgNGEgZGF0YXNldCByZW5hbWluZyBjb2x1bW5zIApgYGB7cn0KdGFibGU0YSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGMoYDE5OTlgLCBgMjAwMGApLCBuYW1lc190byA9ICJ5ZWFyIiwgdmFsdWVzX3RvID0gImNhc2VzIikKYGBgCgpUaWR5aW5nIGRhdGEgaW50byBjZWxscwoKYGBge3J9CnRhYmxlNGIgJT4lIAogIHBpdm90X2xvbmdlcihjKGAxOTk5YCwgYDIwMDBgKSwgbmFtZXNfdG8gPSAieWVhciIsIHZhbHVlc190byA9ICJwb3B1bGF0aW9uIikKYGBgCgpUaWR5IHRhYmxlIDRhCgpgYGB7cn0KdGlkeTRhIDwtIHRhYmxlNGEgJT4lIAogIHBpdm90X2xvbmdlcihjKGAxOTk5YCwgYDIwMDBgKSwgbmFtZXNfdG8gPSAieWVhciIsIHZhbHVlc190byA9ICJjYXNlcyIpCmBgYAoKVGlkeSB0YWJsZSA0YgoKYGBge3J9CnRpZHk0YiA8LSB0YWJsZTRiICU+JSAKICBwaXZvdF9sb25nZXIoYyhgMTk5OWAsIGAyMDAwYCksIG5hbWVzX3RvID0gInllYXIiLCB2YWx1ZXNfdG8gPSAicG9wdWxhdGlvbiIpCmBgYAoKTGVmdCB0byBqb2luIHRhYmxlIDRhIGFuZCB0YWJsZSA0Yi4gCgpgYGB7cn0KbGVmdF9qb2luKHRpZHk0YSwgdGlkeTRiKQpgYGAKTG9hZCBUYWJsZSAyCgpgYGB7cn0KdGFibGUyCmBgYAoKVXNpbmcgcGl2b3Qgd2lkZXIgdG8gY3JlYXRlIGEgbmV3IGNvbHVtbgoKYGBge3J9CnRhYmxlMiAlPiUKICAgIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSB0eXBlLCB2YWx1ZXNfZnJvbSA9IGNvdW50KQpgYGAKCgojIyMjIDEyLjMgUXVlc3Rpb25zCgoqKjI6KiogV2h5IGRvZXMgdGhpcyBjb2RlIGZhaWw/IFBpdm90X2xvbmdlciB3YXMgb21pdHRlZCwgc28gd2VyZSBxdW90YXRpb24gbWFya3MgYXJvdW5kIDE5OTkgYW5kIDIwMDAuIEZpeCBpdCBzbyBpdCB3b3Jrcy4KCk9yaW5pbmFsIENodW5rCmBgYHtyfQp0YWJsZTRhICU+JSAKICBnYXRoZXIoMTk5OSwgMjAwMCwga2V5ID0gInllYXIiLCB2YWx1ZSA9ICJjYXNlcyIpCiM+IEVycm9yIGluIGluZHNfY29tYmluZSgudmFycywgaW5kX2xpc3QpOiBQb3NpdGlvbiBtdXN0IGJlIGJldHdlZW4gMCBhbmQgbgpgYGAKCkZpeGVkIENodW5rCmBgYHtyfQp0YWJsZTRhICU+JSAKICBwaXZvdF9sb25nZXIoYyhgMTk5OWAsIGAyMDAwYCksIG5hbWVzX3RvID0gInllYXIiLCB2YWx1ZXNfdG8gPSAiY2FzZXMiKQpgYGAKClRoYXQgaXMgYWxsIGZvciBDaGFwdGVyIDEyLiBPbiB0byB0aGUgbGFzdCBjaGFwdGVyLgoKCiMjIENoYXB0ZXIgNTogRGF0YSB0cmFuc2Zvcm1hdGlvbgoKUmVhZCBbUjRkcyBDaGFwdGVyIDU6IERhdGEgVHJhbnNmb3JtYXRpb25dKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovdHJhbnNmb3JtLmh0bWwpLCBzZWN0aW9ucyAxLTQuCgpUaW1lIHRvIFtnZXQgc21hbGwuXShodHRwczovL3d3dy55b3V0dWJlLmNvbS93YXRjaD92PUdPcmR6Q0hucHc0KSAKCiMjIyA1LjE6IEludHJvZHVjdGlvbgoKTG9hZCB0aGUgbmVjZXNzYXJ5IGxpYnJhcmllcy4gQXMgdXN1YWwsIHR5cGUgdGhlIGV4YW1wbGVzIGludG8gYW5kIHJ1biB0aGUgY29kZSBjaHVua3MuCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKYGBge3J9CmxpYnJhcnkobnljZmxpZ2h0czEzKQpgYGAKCkxvYWRpbmcgRmxpZ2h0cwpgYGB7cn0KZmxpZ2h0cwpgYGAKCiMjIyA1LjI6IEZpbHRlciByb3dzIHdpdGggYGZpbHRlcigpYAoKU3R1ZHkgRmlndXJlIDUuMSBjYXJlZnVsbHkuIE9uY2UgeW91IGxlYXJuIHRoZSBgJmAsIGB8YCwgYW5kIGAhYCBsb2dpYywgeW91IHdpbGwgZmluZCB0aGVtIHRvIGJlIHZlcnkgcG93ZXJmdWwgdG9vbHMuCgpGaWx0ZXIgZmxpZ2h0cyBieSBkYXkgYW5kIHRpbWUKCmBgYHtyfQpmaWx0ZXIoZmxpZ2h0cywgbW9udGggPT0gMSwgZGF5ID09IDEpCmBgYAoKU2F2ZSB0aGUgcmVzdWx0cyAwMS8wMQpgYGB7cn0KamFuMSA8LSBmaWx0ZXIoZmxpZ2h0cywgbW9udGggPT0gMSwgZGF5ID09IDEpCmBgYAoKU2F2ZSBhbmQgcHJpbnQgdGhlIHJlc3VsdHMgb2YgZmxpZ2h0cyBvbiAxMi8yNQpgYGB7cn0KKGRlYzI1IDwtIGZpbHRlcihmbGlnaHRzLCBtb250aCA9PSAxMiwgZGF5ID09IDI1KSkKYGBgCgpOb3QgdXNpbmcgPT0gZXJyb3IKYGBge3J9CmZpbHRlcihmbGlnaHRzLCBtb250aCA9IDEpCmBgYApGbG9hdGluZyBudW1iZXIgcmVzdWx0cwpgYGB7cn0Kc3FydCgyKSBeIDIgPT0gMgpgYGAKClVzZSBvZiBuZWFyCmBgYHtyfQpuZWFyKHNxcnQoMikgXiAyLCAgMikKYGBgCgpVc2Ugb2YgbmVhcgpgYGB7cn0KbmVhcigxIC8gNDkgKiA0OSwgMSkKYGBgCgpBbGwgZmxpZ2h0cyB0aGF0IGRlcGFydGVkIGluIE5vdiBvciBEZWMKYGBge3J9CmZpbHRlcihmbGlnaHRzLCBtb250aCA9PSAxMSB8IG1vbnRoID09IDEyKQpgYGAKCgpTZ29ydGhhbmQgdG8gZmluZCBhbGwgbm92IGFuZCBkZWMgZmxpZ2h0cwpgYGB7cn0Kbm92X2RlYyA8LSBmaWx0ZXIoZmxpZ2h0cywgbW9udGggJWluJSBjKDExLCAxMikpCmBgYAoKCkZsaWdodHMgdGhhdCB3ZXJlbid0IGRlbGF5ZWQgYnkgbW9yZSB0aGFuIHR3byBob3Vycy4gCmBgYHtyfQpmaWx0ZXIoZmxpZ2h0cywgIShhcnJfZGVsYXkgPiAxMjAgfCBkZXBfZGVsYXkgPiAxMjApKQpgYGAKCkZsaWdodHMgdGhhdCB3ZXJlbid0IGRlbGF5ZWQgYnkgbW9yZSB0aGFuIDIgaG91cnMKYGBge3J9CmZpbHRlcihmbGlnaHRzLCBhcnJfZGVsYXkgPD0gMTIwLCBkZXBfZGVsYXkgPD0gMTIwKQpgYGAKCkNyZWF0aW5nIGRhdGEgZnJhbWUKCmBgYHtyfQpkZiA8LSB0aWJibGUoeCA9IGMoMSwgTkEsIDMpKQpgYGAKCkFwcGx5IGZpbHRlcgpgYGB7cn0KZGYgPC0gdGliYmxlKHggPSBjKDEsIE5BLCAzKSkKZmlsdGVyKGRmLCB4ID4gMSkKYGBgCgpBcHBseSBmaWx0ZXIKYGBge3J9CmZpbHRlcihkZiwgaXMubmEoeCkgfCB4ID4gMSkKYGBgCgojIyMjIDUuMiBRdWVzdGlvbnMKCioqMS4xOioqIEZpbmQgYWxsIGZsaWdodHMgd2l0aCBhIGRlbGF5IG9mIDIgaG91cnMgb3IgbW9yZS4KCmBgYHtyfQpmaWx0ZXIoZmxpZ2h0cywgZGVwX2RlbGF5ID49MTIwKSAKYGBgCgoKKioxLjI6KiogRmxldyB0byBIb3VzdG9uIChJQUggb3IgSE9VKQpgYGB7cn0KZmlsdGVyKGZsaWdodHMsIGRlc3QgPT0gIklBSCIgfCBkZXN0PT0gIkhPVSIpCmBgYAoKCioqMS4zOioqIFdlcmUgb3BlcmF0ZWQgYnkgVW5pdGVkIChVQSksIEFtZXJpY2FuIChBQSksIG9yIERlbHRhIChETCkuCmBgYHtyfQpmaWx0ZXIoZmxpZ2h0cywgY2FycmllciA9PSJVQSIgfCBjYXJyaWVyID09ICJBQSIgfCBjYXJyaWVyID09ICJETCIpCmBgYAoKCioqMS40OioqIERlcGFydGVkIGluIHN1bW1lciAoSnVseSwgQXVndXN0LCBhbmQgU2VwdGVtYmVyKS4KYGBge3J9CmZpbHRlcihmbGlnaHRzLCBtb250aCA9PSI3IiB8IG1vbnRoID09ICI4IiB8IG1vbnRoID09ICI5IikKYGBgCgoKKioxLjU6KiogQXJyaXZlZCBtb3JlIHRoYW4gdHdvIGhvdXJzIGxhdGUsIGJ1dCBkaWRu4oCZdCBsZWF2ZSBsYXRlLgpgYGB7cn0KZmlsdGVyKGZsaWdodHMsIGRlcF9kZWxheSA9PSAwICYgYXJyX2RlbGF5ID49IDEyMCkKYGBgCgoKKioxLjY6KiogV2VyZSBkZWxheWVkIGJ5IGF0IGxlYXN0IGFuIGhvdXIsIGJ1dCBtYWRlIHVwIG92ZXIgMzAgbWludXRlcyBpbiBmbGlnaHQuIFRoaXMgaXMgYSB0cmlja3kgb25lLiBEbyB5b3VyIGJlc3QuCmBgYHtyfQpmaWx0ZXIoZmxpZ2h0cywgZGVwX2RlbGF5ID49IDYwICYgYXJyX2RlbGF5IDw9IDMwKQpgYGAKCgoqKjEuNzoqKiBEZXBhcnRlZCBiZXR3ZWVuIG1pZG5pZ2h0IGFuZCA2YW0gKGluY2x1c2l2ZSkKYGBge3J9CmZpbHRlcihmbGlnaHRzLCBkZXBfdGltZSA+PSAwMDAwICYgZGVwX3RpbWUgPD02MDApCmBgYAoKCioqMjoqKiBBbm90aGVyIHVzZWZ1bCBkcGx5ciBmaWx0ZXJpbmcgaGVscGVyIGlzIGBiZXR3ZWVuKClgLiBXaGF0IGRvZXMgaXQgZG8/IENhbiB5b3UgdXNlIGl0IHRvIHNpbXBsaWZ5IHRoZSBjb2RlIG5lZWRlZCB0byBhbnN3ZXIgdGhlIHByZXZpb3VzIGNoYWxsZW5nZXM/CgpCZXR3ZWVuIGlzIGEgc2hvcnRjdXQgZm9yIGxlc3MgdGhhbiBhbmQgZXF1YWwgdG8gYW5kIGdyZWF0ZXIgdGhhbiBhbmQgZXF1YWwgdG8uIFllcywgMS43IGNvdWxkdmUgYmVlbiBzaG9ydGN1dHRlZCBieSAKYGBge3J9CmZpbHRlcihmbGlnaHRzLCBiZXR3ZWVuKGRlcF90aW1lLCAwICwgNjAwKSkKYGBgCgoKKiozOioqIEhvdyBtYW55IGZsaWdodHMgaGF2ZSBhIG1pc3NpbmcgZGVwX3RpbWU/IDgyNTUgZmxpZ2h0cyBXaGF0IG90aGVyIHZhcmlhYmxlcyBhcmUgbWlzc2luZz8gRGVwYXJ0dXJlIGRlbGF5LCBhaXIgdGltZSwgYXJyaXZhbCB0aW1lLCBhbmQgYXJyaXZhbCBkZWxheS4gV2hhdCBtaWdodCB0aGVzZSByb3dzIHJlcHJlc2VudD8gVGhlIGZsaWdodHMgbmV2ZXIgbGVmdC4gCmBgYHtyfQpzdW0oaXMubmEoZmxpZ2h0cyRkZXBfdGltZSkpCmBgYAoKYGBge3J9CmZpbHRlcihmbGlnaHRzLCBpcy5uYShkZXBfdGltZSkpCmBgYAoKCioqNDoqKiBXaHkgaXMgYE5BIF4gMGAgbm90IG1pc3Npbmc/IE5BIHJhaXNlZCB0byB0aGUgcG93ZXIgb2YgemVybyBhIHZhbHVlLCB6ZXJvLiAgV2h5IGlzIGBOQSB8IFRSVUVgIG5vdCBtaXNzaW5nPyBBbnl0aGluZyAnb3IgdHJ1ZScgaXMgYWx3YXlzIHRydWUuICAgV2h5IGlzIGBGQUxTRSAmIE5BYCBub3QgbWlzc2luZz8gQW55dGhpbmcgICdhbmQgZmFsc2UnICBpcyBhbHdheXMgZmFsc2UuICBDYW4geW91IGZpZ3VyZSBvdXQgdGhlIGdlbmVyYWwgcnVsZT8gKGBOQSAqIDBgIGlzIGEgdHJpY2t5IGNvdW50ZXJleGFtcGxlISkKCgoqKk5vdGU6KiogRm9yIHNvbWUgY29udGV4dCwgc2VlIFt0aGlzIHRocmVhZF0oaHR0cHM6Ly9ibG9nLnJldm9sdXRpb25hbmFseXRpY3MuY29tLzIwMTYvMDcvdW5kZXJzdGFuZGluZy1uYS1pbi1yLmh0bWwpCgoKIyMjIDUuMyBBcnJhbmdlIHdpdGggYGFycmFuZ2UoKWAKCkFycmFuZ2UgZmxpZ2h0cwpgYGB7cn0KYXJyYW5nZShmbGlnaHRzLCB5ZWFyLCBtb250aCwgZGF5KQpgYGAKCnJlb3JkZXIgY29sdW1ucyBieSBkZWNlbmRpbmcgb3JkZXIKYGBge3J9CmFycmFuZ2UoZmxpZ2h0cywgZGVzYyhkZXBfZGVsYXkpKQpgYGAKCkNyZWF0ZSBkYXRhIGZyYW1lCmBgYHtyfQpkZiA8LSB0aWJibGUoeCA9IGMoNSwgMiwgTkEpKQpgYGAKClNvcnQgTWlzc2luZyBWYWx1ZXMKYGBge3J9CmFycmFuZ2UoZGYsIHgpCmBgYAoKU29ydCBtaXNzaW5nIHZhbHVlcwpgYGB7cn0KYXJyYW5nZShkZiwgZGVzYyh4KSkKYGBgCgoKIyMjIyA1LjMgUXVlc3Rpb25zCgoqKjE6KiogSG93IGNvdWxkIHlvdSB1c2UgYGFycmFuZ2UoKWAgdG8gc29ydCBhbGwgbWlzc2luZyB2YWx1ZXMgdG8gdGhlIHN0YXJ0PyAoSGludDogdXNlIGlzLm5hKCkpLiAqKk5vdGU6KiogVGhpcyBvbmUgc2hvdWxkIHN0aWxsIGhhdmUgdGhlIGVhcmxpZXN0IGRlcGFydHVyZSBkYXRlcyBhZnRlciB0aGUgYE5BYHMuICpIaW50OiogV2hhdCBkb2VzIGBkZXNjKClgIGRvPwoKYGBge3J9CmFycmFuZ2UoZmxpZ2h0cywgZGVzYyhpcy5uYShkZXBfZGVsYXkpKSkKYGBgCgoKCioqMjoqKiBTb3J0IGZsaWdodHMgdG8gZmluZCB0aGUgbW9zdCBkZWxheWVkIGZsaWdodHMuIEZpbmQgdGhlIGZsaWdodHMgdGhhdCBsZWZ0IGVhcmxpZXN0LiAKTW9zdCBkZWxheWVkIGZsaWdodHMKYGBge3J9CmFycmFuZ2UoZmxpZ2h0cywgZGVzYyhkZXBfZGVsYXkpKQpgYGAKCkZsaWdodHMgdGhhdCBsZWZ0IHRoZSBlYXJsaWVzdApgYGB7cn0KYXJyYW5nZShmbGlnaHRzLCBkZXBfZGVsYXkpCmBgYAoKClRoaXMgcXVlc3Rpb24gaXMgYXNraW5nIGZvciB0aGUgZmxpZ2h0cyB0aGF0IHdlcmUgbW9zdCBkZWxheWVkIChsZWZ0IGxhdGVzdCBhZnRlciBzY2hlZHVsZWQgZGVwYXJ0dXJlIHRpbWUpIGFuZCBsZWFzdCBkZWxheWVkIChsZWZ0IGFoZWFkIG9mIHNjaGVkdWxlZCB0aW1lKS4KCgoqKjM6KiogU29ydCBmbGlnaHRzIHRvIGZpbmQgdGhlIGZhc3Rlc3QgZmxpZ2h0cy4gSW50ZXJwcmV0IGZhc3Rlc3QgdG8gbWVhbiBzaG9ydGVzdCB0aW1lIGluIHRoZSBhaXIuCgpGYXN0ZXN0IGZsaWdodHMKCmBgYHtyfQphcnJhbmdlKGZsaWdodHMsIGFpcl90aW1lKQpgYGAKCipPcHRpb25hbCBjaGFsbGVuZ2U6KiBmYXN0ZXN0IGZsaWdodCBjb3VsZCByZWZlciB0byBmYXN0ZXN0IGFpciBzcGVlZC4gU3BlZWQgaXMgbWVhc3VyZWQgaW4gbWlsZXMgcGVyIGhvdXIgYnV0IHRpbWUgaXMgbWludXRlcy4gQXJyYW5nZSB0aGUgZGF0YSBieSBmYXN0ZXN0IGFpciBzcGVlZC4KCgoqKjQ6KiogV2hpY2ggZmxpZ2h0cyB0cmF2ZWxsZWQgdGhlIGxvbmdlc3Q/IFdoaWNoIHRyYXZlbGxlZCB0aGUgc2hvcnRlc3Q/CkZsaWdodHMgdGhhdCB0cmF2ZWxsZWQgdGhlIGxvbmdlc3QKYGBge3J9CmFycmFuZ2UoZmxpZ2h0cywgZGVzYyhkaXN0YW5jZSkpCmBgYAoKRmxpZ2h0cyB0cmF2ZWxsZWQgdGhlIHNob3J0ZXN0CmBgYHtyfQphcnJhbmdlKGZsaWdodHMsIGRpc3RhbmNlKQpgYGAKCgojIyMgNS40IFNlbGVjdCBjb2x1bW5zIHdpdGggYHNlbGVjdCgpYAoKU2VsZWN0IGNvbHVtbnMgYnkgbmFtZQpgYGB7cn0Kc2VsZWN0KGZsaWdodHMsIHllYXIsIG1vbnRoLCBkYXkpCmBgYAoKClNlbGVjdCBhbGwgY29sdW1ucyBidHduIHllYXIgYW5kIGRheSAoaW52bHVzaXZlKQpgYGB7cn0Kc2VsZWN0KGZsaWdodHMsIHllYXI6ZGF5KQpgYGAKClNlbGVjdCBhbGwgY29sdW1ucyBleGNlcHQgdGhvc2UgZnJvbSB5ZWFyIHRvIGRheSAoaW5jbHVzaXZlKQoKYGBge3J9CnNlbGVjdChmbGlnaHRzLCAtKHllYXI6ZGF5KSkKYGBgCgpSZW5hbWUgdmFyaWFibGVzCmBgYHtyfQpyZW5hbWUoZmxpZ2h0cywgdGFpbF9udW0gPSB0YWlsbnVtKQpgYGAKCgptb3ZlIHZhcmlhYmxlcyB0byBzdGFydCBvZiBkYXRhIGZyYW1lCmBgYHtyfQpzZWxlY3QoZmxpZ2h0cywgdGltZV9ob3VyLCBhaXJfdGltZSwgZXZlcnl0aGluZygpKQpgYGAKCgojIyMjIDUuNCBRdWVzdGlvbnMKCioqMToqKiBCcmFpbnN0b3JtIGFzIG1hbnkgd2F5cyBhcyBwb3NzaWJsZSB0byBzZWxlY3QgYGRlcF90aW1lYCwgYGRlcF9kZWxheWAsIGBhcnJfdGltZWAsIGFuZCBgYXJyX2RlbGF5YCBmcm9tIGZsaWdodHMuIEZpbmQgYXQgbGVhc3QgdGhyZWUgd2F5cy4KdXNlIHRoZSBkZXNsZWN0IGZ1bmN0aW9uCmBgYHtyfQpzZWxlY3QoZmxpZ2h0cywgZGVwX3RpbWUsIGRlcF9kZWxheSwgYXJyX3RpbWUsIGFycl9kZWxheSkKYGBgCgpVc2UgdGhlIHN0YXJ0cyB3aXRoIGZ1bmN0aW9uCmBgYHtyfQpzZWxlY3QoZmxpZ2h0cywgc3RhcnRzX3dpdGgoJ2RlcCcpLCBzdGFydHNfd2l0aCgnYXJyJykpCmBgYAoKdXNlIGNvbnRhaW5zKCkKYGBge3J9CnNlbGVjdChmbGlnaHRzLCBjb250YWlucygnZGVsYXlzJyksIGNvbnRhaW5zKCd0aW1lJykpIApgYGAKCgoqKjI6KiogV2hhdCBoYXBwZW5zIGlmIHlvdSBpbmNsdWRlIHRoZSBuYW1lIG9mIGEgdmFyaWFibGUgbXVsdGlwbGUgdGltZXMgaW4gYSBgc2VsZWN0KClgIGNhbGw/CgpUaGUgdmFyaWFibGVzIHlvdSByZXBlYXQgd2lsbCBiZSBvbWl0dGVkCgoKKiozOioqIFdoYXQgZG9lcyB0aGUgYG9uZV9vZigpYCBmdW5jdGlvbiBkbz8gV2h5IG1pZ2h0IGl0IGJlIGhlbHBmdWwgaW4gY29uanVuY3Rpb24gd2l0aCB0aGlzIHZlY3Rvcj8KCmB2YXJzIDwtIGMoInllYXIiLCAibW9udGgiLCAiZGF5IiwgImRlcF9kZWxheSIsICJhcnJfZGVsYXkiKWAKCk9uZV9vZigpIGFsbG93cyB5b3UgdG8gc2VsZWN0IHBhcnRzIG9mIHRoZSBkYXRhZnJhbWUuIFRoZXJlIG1heSBvbmx5IGJlIGEgc2V0IG51bWJlciBvZiBjb2x1bW5zIGFuZCBpbmZvcm1hdGlvbi4gCgoKKio0OioqIERvZXMgdGhlIHJlc3VsdCBvZiBydW5uaW5nIHRoZSBmb2xsb3dpbmcgY29kZSBzdXJwcmlzZSB5b3U/IEhvdyBkbyB0aGUgc2VsZWN0IGhlbHBlcnMgZGVhbCB3aXRoIGNhc2UgYnkgZGVmYXVsdD8gSG93IGNhbiB5b3UgY2hhbmdlIHRoYXQgZGVmYXVsdD8KCmBzZWxlY3QoZmxpZ2h0cywgY29udGFpbnMoIlRJTUUiKSlgCgpgYGB7cn0Kc2VsZWN0KGZsaWdodHMsIGNvbnRhaW5zKCdUSU1FJykpCmBgYAoKWWVzLCBiZWNhdXNlIFIgaXMgY2FzZSBzZW5zaXRpdmUgYnV0IGFwcGFyZW50bHkgY29udGFpbnMoKSBpcyBub3QuCgo=